package com.chenfan.magic.validator;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.chenfan.magic.base.R;
import com.chenfan.magic.base.S;
import com.chenfan.magic.entity.Isv;
import com.chenfan.magic.entity.RequestParamModel;
import com.chenfan.magic.entity.TTLDetailModel;
import com.chenfan.magic.entity.TTLModel;
import com.chenfan.magic.utils.*;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 请求组检验器
 *
 * @author 周夕
 * @date 2020-02-26 17:30
 */
@Slf4j
public class RequestParamsValidator {

    /**
     * 校验预请求变量组
     *
     * @param preRequestParams
     * @return
     */
    public R validate(boolean debug, boolean paramSwitch, String preRequestParams, Isv isv, TTLModel ttlModel) {
        TTLDetailModel requestParamsValidatorTTL = new TTLDetailModel();
        requestParamsValidatorTTL.start("RequestParamsValidator");
        Map<String, Object> requestParamMap = Maps.newHashMap();
        HttpServletRequest request = WebKit.getRequest();
        try {
            if (StringKit.isNotWhite(preRequestParams)) {
                //1.获取脚本预请求组数据.
                List<RequestParamModel> requestParamModels = FastJsonKit.toList(preRequestParams, RequestParamModel.class);
                Map<String, Object> paramMap = WebKit.getParams(request);
                Map<String, String> headerMap = WebKit.getMap4Header(request);
                String cache = getParam(request, paramMap, headerMap, "cache");
                if (StringKit.isNotWhite(cache)) {
                    requestParamMap.put("cache", cache);
                }
                String removeCache = getParam(request, paramMap, headerMap, "removeCache");
                if (StringKit.isNotWhite(removeCache)) {
                    requestParamMap.put("removeCache", removeCache);
                }
                String reqParamSwitch = getParam(request, paramMap, headerMap, "paramSwitch");
                if (StringKit.isNotWhite(reqParamSwitch)) {
                    requestParamMap.put("paramSwitch", reqParamSwitch);
                }
                log.info("==== 预入参组 ====> \n" + FastJsonKit.toJSONString(requestParamModels));
                log.info("==== Header域 ====> \n" + FastJsonKit.map2Jsonstring(headerMap));
                log.info("==== Param域 ====> \n" + FastJsonKit.map2Jsonstring(paramMap));
                //2.参数校验
                for (RequestParamModel rpm : requestParamModels) {
                    if (rpm.getEnable()) {
                        String param = "";
                        //开发模式下, 直接拿模型的值
                        if ((debug && paramSwitch) || ("config".equalsIgnoreCase(reqParamSwitch))) {
                            param = rpm.getValue();
                            //生产模式下
                        } else {
                            if (rpm.getIsRequired() && !hasParam(request, paramMap, headerMap, rpm.getKey())) {
                                if (StringKit.isNotWhite(rpm.getDefaultValue())) {
                                    param = rpm.getDefaultValue();
                                } else {
                                    return S.fail(S.MQL_INVAILD_REQUEST_PARAM, " => " + (StringKit.isNotBlank(rpm.getValidatorExplain()) ? rpm.getValidatorExplain() : (rpm.getApiExplain() + " 必传!")));
                                }
                            } else {
                                param = getParam(request, paramMap, headerMap, rpm.getKey());
                            }
                        }

                        //判定非空
                        if (rpm.getIsNotNull() && StringKit.isBlank(param)) {
                            if (StringKit.isNotWhite(rpm.getDefaultValue())) {
                                param = rpm.getDefaultValue();
                            } else {
                                return S.fail(S.MQL_INVAILD_REQUEST_PARAM, " => " + (StringKit.isNotBlank(rpm.getValidatorExplain()) ? rpm.getValidatorExplain() : (rpm.getApiExplain() + " 不能为空!")));
                            }
                        }
                        //防注入过滤
                        if (rpm.getAntInfusion()) {
                            param = AntiSqlInjectionKit.filter(param);
                        }
                        //防止跨站脚本过滤
                        if (rpm.getAntXss()) {
                            param = new XssKit().filter(param);
                        }
                        //转型处理, 考虑通过JSON处理.
                        //数组类型 => List
                        if (ValidateKit.isArray(param)) {
                            List<Object> listTmp = FastJsonKit.toList(param, Object.class);
                            requestParamMap.put(rpm.getKey(), listTmp);
                            //对象数组类型 => List<Map>
                        } else if (ValidateKit.isJsonArray(param)) {
                            List<Map<String, Object>> listMapTmp = JSON.parseObject(param, new TypeReference<List<Map<String, Object>>>() {
                            });
                            requestParamMap.put(rpm.getKey(), listMapTmp);
                            //对象类型 => Map
                        } else if (ValidateKit.isJsonObject(param)) {
                            Map<String, Object> mapTmp = FastJsonKit.jsonstring2Map(param);
                            requestParamMap.put(rpm.getKey(), mapTmp);
                            //基本类型 => 正则处理
                        } else {
                            if (StringKit.isNotBlank(rpm.getRegx()) && !ValidateKit.isMatch(Pattern.compile(rpm.getRegx()), param)) {
                                if (StringKit.isNotWhite(rpm.getDefaultValue())) {
                                    param = rpm.getDefaultValue();
                                } else {
                                    return S.fail(S.MQL_INVAILD_REQUEST_PARAM, " => " + (StringKit.isNotBlank(rpm.getRegxTip()) ? rpm.getRegxTip() : (StringKit.isNotBlank(rpm.getValidatorExplain()) ? rpm.getValidatorExplain() : (rpm.getApiExplain() + " 正则校验失败! => " + param))));
                                }
                            }
                            requestParamMap.put(rpm.getKey(), param);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return S.fail(S.MQL_INVAILD_REQUEST_PARAMS);
        }
        ttlModel.getValidator().put(requestParamsValidatorTTL.end());
        return R.success().put(requestParamMap);
    }

    /**
     * 获取参数
     *
     * @param key
     * @return
     * @throws Exception
     */
    public String getParam(HttpServletRequest request, Map<String, Object> postParam, Map<String, String> headerParam, String key) throws Exception {
        String param = request.getParameter(key);
        if (StringKit.isWhite(param)) {
            param = postParam.get(key) + "";
        }
        if (StringKit.isWhite(param)) {
            param = (String)headerParam.get(key);
        }
        return param;
    }

    /**
     * 是否含有参数
     *
     * @param key
     * @return
     * @throws Exception
     */
    public boolean hasParam(HttpServletRequest request, Map<String, Object> postParam, Map<String, String> headerParam, String key) throws Exception {
        Map<String, String[]> parameterMap = request.getParameterMap();
        return (parameterMap != null && parameterMap.containsKey(key))
                || StringKit.isNotBlank(request.getParameter(key))
                || postParam.containsKey(key)
                || headerParam.containsKey(key);
    }
}
